// @ts-nocheck
import {Renderer} from 'amis';
import {RendererProps, IScopedContext,Icon} from 'amis';
import {ActionObject, autobind} from 'amis-core';
import {Button} from 'amis-ui';
import React from 'react';
import './ajcaptcha.css';
import {CSSTransition} from 'react-transition-group';
import defaultImg from './default.png';
import CryptoJS from 'crypto-js';

type blockSize = {
  width: any;
  height: any;
};
type setSize = {
  imgHeight: number;
  imgWidth: number;
  barHeight: number;
  barWidth: number;
};

type imgSize = {
  width: any;
  height: any;
};
type AJCaptchaState = {
  isSlideShow: boolean;
  imgSize: imgSize;
  blockSize: blockSize;
  setSize: setSize;
  backImgBase: string | null; // 验证码背景图片
  blockBackImgBase: string | null; // 验证滑块的背景图片
  backToken: string; // 后端返回的唯一token值
  startMoveTime: any; //移动开始的时间
  endMovetime: any; //移动结束的时间
  tipsBackColor: string; //提示词的背景颜色
  secretKey: string; //后端返回的加密秘钥 字段
  captchaType: string;
  moveBlockBackgroundColor: string;
  leftBarBorderColor: string;
  iconColor: string;
  iconClass: string;
  barAreaLeft: number;
  barAreaOffsetWidth: number;
  startLeft: any;
  moveBlockLeft: any;
  leftBarWidth: any;
  status: boolean; //鼠标状态
  isEnd: boolean; //是够验证完成
  passFlag: any;
  tipWords: string;
  text: string;
};
export interface AJCaptchaRendererProps extends RendererProps {
  fieldName?: string;
  captchaType?: string;
  getCaptchaUrl: string;
  checkCaptchaUrl: string;
  mode: any;
  vSpace: number;
  barSize: any;
  showRefresh: any;
  transitionWidth: any;
  finishText: any;
  transitionLeft: any;
}
/**
 * @word 要加密的内容
 * @keyWord String  服务器随机返回的关键字
 *  */
export function aesEncrypt(word: string, keyWord = 'XwKsGlMcdPMEhR1B') {
  const key = CryptoJS.enc.Utf8.parse(keyWord);
  const srcs = CryptoJS.enc.Utf8.parse(word);
  const encrypted = CryptoJS.AES.encrypt(srcs, key, {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7
  });
  return encrypted.toString();
}

@Renderer({
  test: /\baj-captcha-renderer$/,
  name: 'aj-captcha-renderer'
})
export default class AJCaptchaRenderer extends React.Component<
  AJCaptchaRendererProps,
  AJCaptchaState
> {
  private divRef : React.RefObject<HTMLDivElement>;
  //组件间通信 把需要被引用的组件设置一个 name 值，然后其他组件就可以通过这个 name 与其通信
  constructor(props: AJCaptchaRendererProps, context: IScopedContext) {
    super(props);

    this.divRef = React.createRef();
    console.log(this.divRef.current?.offsetLeft,this.divRef.current?.offsetWidth)
    this.state = {
      isSlideShow: false,
      imgSize: {
        width: '310px',
        height: '200px'
      },
      blockSize: {
        width: '50px',
        height: '50px'
      },
      setSize: {
        imgHeight: 200,
        imgWidth: 310,
        barHeight: 40,
        barWidth: 310
      },
      backImgBase: '', // 验证码背景图片
      blockBackImgBase: '', // 验证滑块的背景图片
      backToken: '', // 后端返回的唯一token值
      startMoveTime: 0, //移动开始的时间
      endMovetime: 0, //移动结束的时间
      tipsBackColor: '', //提示词的背景颜色
      secretKey: '', //后端返回的加密秘钥 字段
      captchaType: 'blockPuzzle',
      moveBlockBackgroundColor: 'rgb(255, 255, 255)',
      leftBarBorderColor: '',
      iconColor: '',
      iconClass: '',
      barAreaLeft: 0,
      barAreaOffsetWidth: 0,
      startLeft: null,
      moveBlockLeft: null,
      leftBarWidth: null,
      status: false, //鼠标状态
      isEnd: false, //是够验证完成
      passFlag: '',
      tipWords: '',
      text: '向右滑动完成验证'
    };
  }

  /**
   * 派发自定义事件
   * @param eventData
   * @returns {Promise<void>}
   */
  // @ts-ignore
  @autobind
  async dispatchChangeEvent(eventData: any = {}) {
    const {dispatchEvent} = this.props;
    const rendererEvent = await dispatchEvent(
      'successCallback',
      JSON.stringify(eventData)
    );
    if (rendererEvent?.prevented) {
      return;
    }
  }

  componentWillUnmount() {}
  componentDidMount() {
    this.uuid();
    this.getData();
    this.init();
    console.log('----divRef---',this.divRef)
  }

  // 初始话 uuid
  uuid() {
    var s: any[] = [];
    var hexDigits = '0123456789abcdef';
    for (var i = 0; i < 36; i++) {
      s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
    }
    s[14] = '4'; // bits 12-15 of the time_hi_and_version field to 0010
    s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
    s[8] = s[13] = s[18] = s[23] = '-';

    var slider = 'slider' + '-' + s.join('');
    var point = 'point' + '-' + s.join('');
    // 判断下是否存在 slider
    console.log(localStorage.getItem('slider'));
    if (!localStorage.getItem('slider')) {
      localStorage.setItem('slider', slider);
    }
    if (!localStorage.getItem('point')) {
      localStorage.setItem('point', point);
    }
  }
  init() {
    var _this = this;

    window.removeEventListener('touchmove', function (e) {
      _this.move(e);
    });
    window.removeEventListener('mousemove', function (e) {
      _this.move(e);
    });

    //鼠标松开
    window.removeEventListener('touchend', function () {
      _this.end();
    });
    window.removeEventListener('mouseup', function () {
      _this.end();
    });

    window.addEventListener('touchmove', function (e) {
      _this.move(e);
    });
    window.addEventListener('mousemove', function (e) {
      _this.move(e);
    });

    //鼠标松开
    window.addEventListener('touchend', function () {
      _this.end();
    });
    window.addEventListener('mouseup', function () {
      _this.end();
    });
  }
  getData() {
    this.props.env
      .fetcher(this.props.getCaptchaUrl, {
        captchaType: this.state.captchaType,
        clientUid: localStorage.getItem('slider'),
        ts: Date.now()
      })
      .then((response: any) => {
        console.log('---getData---', response);
        const res = response.data;
        if (res.repCode === '0000') {
          this.setState({
            backImgBase: res.repData.originalImageBase64,
            blockBackImgBase: res.repData.jigsawImageBase64,
            backToken: res.repData.token,
            secretKey: res.repData.secretKey
          });
        }
        // 请求次数超限
        if (res.repCode == '6201') {
          this.setState({
            backImgBase: null,
            blockBackImgBase: null,
            leftBarBorderColor: '#d9534f',
            iconColor: '#fff',
            iconClass: 'icon-close',
            passFlag: false,
            tipWords: res.repMsg
          });
          setTimeout(() => {
            this.setState({
              tipWords: ''
            });
          }, 1000);
        }
      })
      .catch(error => {
        console.log('---getData-->', error);
      });
  }
  refresh = () => {
    this.getData();
    this.setState({
      moveBlockLeft: '',
      leftBarWidth: '',
      text: '向右滑动完成验证',
      moveBlockBackgroundColor: '#fff',
      leftBarBorderColor: '#337AB7',
      iconColor: '#fff',
      status: false,
      isEnd: false
    });
  };
  setBarArea = (event: any) => {
    let barAreaLeft = event && event.getBoundingClientRect().left;
    let barAreaOffsetWidth = event && event.offsetWidth;
    this.setState({barAreaLeft: barAreaLeft});
    this.setState({barAreaOffsetWidth: barAreaOffsetWidth});
  };

  start = (e: any) => {
    e = e || window.event;
    if (!e.touches) {
      //兼容PC端
      var x = e.clientX;
    } else {
      //兼容移动端
      var x = e.touches[0].pageX;
    }
    this.setState({startLeft: Math.floor(x - this.state.barAreaLeft)});
    this.setState({
      startMoveTime: this.state.startMoveTime + new Date().getTime()
    }); //开始滑动的时间
    if (this.state.isEnd == false) {
      this.setState({
        text: '',
        moveBlockBackgroundColor: '#337ab7',
        leftBarBorderColor: '#337AB7',
        iconColor: '#fff',
        status: true
      });
      this.setState({text: ''});
      e.stopPropagation();
    }
  };

  move = (e: any) => {
    e = e || window.event;
    if (this.state.status && this.state.isEnd == false) {
      if (!e.touches) {
        //兼容PC端
        var x = e.clientX;
      } else {
        //兼容移动端
        var x = e.touches[0].pageX;
      }
      var bar_area_left = this.state.barAreaLeft;
      var move_block_left = x - bar_area_left; //小方块相对于父元素的left值
      if (
        move_block_left >=
        this.state.barAreaOffsetWidth - this.state.blockSize.width / 2 - 2
      ) {
        move_block_left =
          this.state.barAreaOffsetWidth - this.state.blockSize.width / 2 - 2;
      }
      if (move_block_left <= 0) {
        move_block_left = this.state.blockSize.width / 2;
      }
      //左边界
      if (move_block_left <= this.state.startLeft) {
        move_block_left = this.state.startLeft;
      }
      //右边界
      if (move_block_left > this.state.startLeft+this.state.setSize.imgWidth-32-15) {
        move_block_left = this.state.startLeft+this.state.setSize.imgWidth-32-15;
      }
      //拖动后小方块的left值
      this.setState({
        moveBlockLeft: move_block_left - this.state.startLeft + 'px'
      });
      this.setState({
        leftBarWidth: move_block_left - this.state.startLeft + 'px'
      });
    }
  };

  end = () => {
    this.setState({endMovetime: this.state.endMovetime + new Date().getTime()});
    var _this = this;
    //判断是否重合
    if (this.state.status && this.state.isEnd == false) {
      var moveLeftDistance = parseInt(
        (this.state.moveBlockLeft || '').replace('px', '')
      );
      moveLeftDistance = (moveLeftDistance * 310) / this.state.setSize.imgWidth;
      let data = {
        captchaType: this.state.captchaType,
        pointJson: this.state.secretKey
          ? aesEncrypt(
              JSON.stringify({x: moveLeftDistance, y: 5.0}),
              this.state.secretKey
            )
          : JSON.stringify({x: moveLeftDistance, y: 5.0}),
        token: this.state.backToken,
        clientUid: localStorage.getItem('slider'),
        ts: Date.now()
      };
      // 调用校验验证
      this.props.env
        .fetcher(this.props.checkCaptchaUrl, data)
        .then((response: any) => {
          const res = response.data;
          if (res.repCode == '0000') {
            this.setState({isEnd: true});
            this.setState({passFlag: true});
            this.setState({tipWords: ''});
            console.log(
              '---this.state.endMovetime-this.state.startMoveTime--',
              this.state.endMovetime,
              this.state.startMoveTime
            );
            this.setState({
              tipWords: `验证成功`
            });
            setTimeout(() => {
              this.setState({tipWords: ''});
              this.refresh();
            }, 1000);
            console.log('----this.props.dispatchEvent---');
            this.dispatchChangeEvent(data);
            this.setState({isSlideShow: false});
          } else {
            this.setState({
              isEnd: true,
              moveBlockBackgroundColor: '#d9534f',
              leftBarBorderColor: '#d9534f',
              iconColor: '#fff',
              iconClass: 'icon-close',
              passFlag: false,
              tipWords: res.repMsg || '验证失败'
            });
            setTimeout(() => {
              this.refresh();
              this.setState({
                tipWords: ''
              });
            }, 1000);
          }
        });
      this.setState({status: false});
    }
  };
  doAction(action: ActionObject, data: object, throwErrors: boolean): any {
    console.log('---doAction---', action, data, throwErrors);
  }
  closeBox = () => {
    this.setState({isSlideShow: false});
  };
  showBox = () => {
    this.setState({isSlideShow: true});
    console.log(this.divRef,this.divRef.current?.offsetLeft,this.divRef.current?.offsetWidth)
  };

  render() {
    const {
      dispatchEvent,
      captchaType,
      mode,
      vSpace,
      barSize,
      showRefresh,
      transitionWidth,
      finishText,
      transitionLeft
    } = this.props;
    return (
      <div>
        <Button
          type="button"
          level="link"
          onClick={() => this.showBox()}
        >
          验证码
        </Button>
        <div
          className="mask"
          style={{display: this.state.isSlideShow ? 'block' : 'none'}}
        >
          <div
            className="verifybox"
            style={{maxWidth: parseInt(this.state.imgSize.width) + 30 + 'px'}}
          >
            <div className="verifybox-top">
              <div className="title_metnq">
                <p className="titleTop_metnq">安全验证</p>
                <p className="titleBold_metnq">请拖动下方滑块完成拼图</p>
              </div>
              <span className="verifybox-close" onClick={() => this.closeBox()}>
              </span>
            </div>
            <div className="verifybox-bottom" style={{padding: '15px'}}
                 ref={this.divRef}>
              {/* 验证容器 */}
              <div style={{position: 'relative'}} className="stop-user-select">
                <div
                  className="verify-img-out"
                  style={{height: this.state.setSize.imgHeight + vSpace}}
                >
                  <div
                    className="verify-img-panel"
                    style={{
                      width: this.state.setSize.imgWidth,
                      height: this.state.setSize.imgHeight
                    }}
                  >
                    {this.state.backImgBase ? (
                      <img
                        src={'data:image/png;base64,' + this.state.backImgBase}
                        alt=""
                        style={{
                          width: '100%',
                          height: '100%',
                          display: 'block'
                        }}
                      />
                    ) : (
                      <img
                        src={defaultImg}
                        alt=""
                        style={{
                          width: '100%',
                          height: '100%',
                          display: 'block'
                        }}
                      />
                    )}
                    <CSSTransition
                      in={this.state.tipWords.length > 0}
                      timeout={150}
                      classNames="tips"
                      unmountOnExit
                    >
                      <span
                        className={
                          this.state.passFlag
                            ? `${'verify-tips'} ${'suc-bg'}`
                            : `${'verify-tips'} ${'err-bg'}`
                        }
                      >
                        {this.state.passFlag?<Icon icon="success-circle" vendor="fa"/>:
                            <Icon icon="close-circle" vendor="fa" />}
                        <p>{this.state.tipWords}</p>
                      </span>
                    </CSSTransition>
                  </div>
                </div>
                <div
                    className="verify-sub-block"
                    style={{
                      width:
                          Math.floor(
                              (this.state.setSize.imgWidth * 47) / 310
                          ) + 'px',
                      height: this.state.setSize.imgHeight,
                      top:
                          '-' +vSpace+
                          'px',
                      backgroundSize:
                          this.state.setSize.imgWidth +
                          ' ' +
                          this.state.setSize.imgHeight,

                      left: this.state.moveBlockLeft,
                      transition: transitionLeft,
                    }}
                >
                  <img
                      src={
                          'data:image/png;base64,' +
                          this.state.blockBackImgBase
                      }
                      alt=""
                      style={{
                        width: '100%',
                        height: '100%',
                        display: 'block'
                      }}
                  />
                </div>
                <div className="slides-metnq">
                  <div className="track-metnq"></div>
                  <div className="slider-metnq"
                       style={{
                         left: this.state.moveBlockLeft,
                         transition: transitionLeft
                       }}
                       onTouchStart={e => this.start(e)}
                       onMouseDown={e => this.start(e)}
                  ><i></i><i></i><i></i></div>
                </div>
                <div className="toolbox_metnq">
                  <span className="refreshBtn_metnq" onClick={() => this.refresh()}></span>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    );
  }
}
